#ifndef VENUS_COMMON_MEMORY_H
#define VENUS_COMMON_MEMORY_H

#include "venus.h"

#include <stdlib.h>

#include <list>

namespace venus {
class ReferenceCounted {
 public:
  ReferenceCounted() : reference_count_(0) { }
  void inc_reference_count() { ++reference_count_; }
  void dec_reference_count() { --reference_count_; }
  int reference_count() const { return reference_count_; }
 private:
  DISABLE_COPY_AND_ASSIGN(ReferenceCounted);
  int reference_count_;
};

template<typename T>
class SharedPtr {
 public:
  explicit SharedPtr(T *p) : p_(p) { }
  SharedPtr(const SharedPtr<T> &ptr) {
    p_ = ptr.p_;
    if (NULL != p_) p_->inc_reference_count();
  }
  SharedPtr &operator=(const SharedPtr<T> &ptr) {
    if (NULL != ptr.p_) ptr.p_->inc_reference_count();
    if (NULL != p_) p_->dec_reference_count();
    if (p_->reference_count() == 0) delete p_;
    p_ = ptr.p_;
    return *this;
  }
  ~SharedPtr() {
    if (NULL != p_) p_->dec_reference_count();
    if (p_->reference_count() == 0) delete p_;  
  }
  T *operator->() { return p_; }
  const T *operator->() const { return p_; }
  bool IsNull() const { return NULL == p_; }
 private:
  T *p_;
};

template<typename T>
class MemPool {
	typedef std::list<T*> BlockList;
public:
	MemPool(uint32_t block_size = 512) : block_size_(block_size) { 
    this->Alloc(); 
  }

	virtual ~MemPool() { 
		for (typename BlockList::iterator it = blocks_.begin(); 
        it != blocks_.end(); ++it) { free(*it); }
	}

	T* Alloc(uint32_t size) {
		if (current_block_pos_ + size > block_size_ ) {
			block_size_ = block_size_ > size ? block_size_ : size;
			this->Alloc();
		}
		T* ret = current_block_ + current_block_pos_; 
    current_block_pos_ += size;
		return ret;
	}

private:
	void Alloc() {
		current_block_ = (T*)malloc(sizeof(T) * block_size_);
		blocks_.push_back(current_block_);
		current_block_pos_ = 0;
	}
	
private:		
	BlockList blocks_;
	uint32_t block_size_;
	T* current_block_;
	uint32_t current_block_pos_;
};

/* the following are kd acceleration specific
class KdNodePool : protected MemPool<KdTreeNode> {
public:
	KdNodePool( const uint32_t a_BlockSize = 512 ) : MemPool<KdTreeNode>( a_BlockSize ) { }

	KdTreeNode* AllocNodePair() { return Alloc( 2 ); }	
};

typedef MemPool<uint32_t> PrimNumPool;*/

}; // namespace venus

#endif // VENUS_COMMON_MEMORY_H
